package cn.base.web.support.transcode;

import cn.base.web.cahe.DefaultCacheService;
import cn.base.web.support.sysenum.SysCodeService;
import cn.rengy.isql.Dao;
import cn.rengy.isql.GetSqlService;
import cn.rengy.isql.SqlEntity;
import cn.rengy.lang.ObjectTranscoder;
import cn.rengy.tool.core.GenericTokenParser;
import cn.rengy.tool.core.TokenHandler;
import cn.rengy.tool.core.util._Utils;
import cn.rengy.util.ExceptionPrintUtils;
import com.baomidou.dynamic.datasource.annotation.DS;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

/**
 * 数据格式化
 */
@Component
@Slf4j
@DS("admin")
public class DefaultObjectTranscoder implements ObjectTranscoder {
	@Autowired(required = false)
	private Dao dao;
	@Autowired
	private SysCodeService sysCodeService;

	@Autowired
	private DefaultCacheService cacheService;

	private static final String sql="select * from sys_transcode_detail where deleted=0 and format_key=?";

	private List<TranscodeColumn> getTrancodeColumn(String transCodeKey){
		//sys_sql加了是否转义之后这里可以改成不缓存空值
		//TODO 改成guava cache 空值 可以设置过期时间
        try {
            return cacheService.getCache("transCodeCache", transCodeKey, new Callable<List<TranscodeColumn>>() {
                @Override
                public List<TranscodeColumn> call() throws Exception {
                    List<TranscodeColumn> list = dao.queryForBeanList(sql, TranscodeColumn.class, transCodeKey);
                    return list;
                }
            });
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

	public void transcode(String transCodeKey,List<Map<String,Object>> list){
		if(list!=null&&list.size()>0){
			List<TranscodeColumn> columnList=getTrancodeColumn(transCodeKey);
			transcode(columnList,list);
		}
	}
	public void transcode(String transCodeKey,Map<String,Object> map){
		if(map!=null){
			List<TranscodeColumn> columnList=getTrancodeColumn(transCodeKey);
			List<Map<String,Object>> list=new ArrayList<Map<String,Object>>(1);
			list.add(map);
			transcode(columnList,list);
		}
	}
    @Autowired(required = false)
    private GetSqlService getSqlService;

    /**
     * 默认从admin库获取
     * @param sqlName
     * @return
     */
    public List<Map<String, Object>> queryBySqlname(String sqlName){
        SqlEntity sqlEntity= getSqlService.getSqlEntityByName(sqlName);
        return this.dao.queryForList(false,sqlEntity.getSql_value());
    }
	
	private void transcode(List<TranscodeColumn> columnList,List<Map<String,Object>> list){
		if(columnList!=null&&columnList.size()>0){
			for(TranscodeColumn column:columnList){
				String columnName=column.getColumnName();
				String newColumnName=column.getNewColumnName();
				if(newColumnName==null){
					newColumnName=columnName.concat("DisplayName");
				}
				String formatType=column.getFormatType();
				try{
					
						String codeKey=column.getCodeKey();
						TransTypeEnum transTypeEnum = TransTypeEnum.valueOf(formatType);
						switch (transTypeEnum) {
					        case translate:
					        	String sqlname=column.getSqlName();
					        	List<Map<String, Object>> codeList=null;
					        	if(StringUtils.isNotBlank(sqlname)) {
                                    //微服务中 区分从admin库还是本服务库master 查询
					        		codeList = queryBySqlname(codeKey);
					        	}else {
					        		codeList = sysCodeService.query(codeKey);
					        	}
					        	for(Map<String,Object> map:list) {
					        		Object fieldValue=map.get(columnName);
									if(fieldValue==null) {
										fieldValue="";
									}
									//Object newValue=fieldValue;
									if(StringUtils.isNotBlank(sqlname)) {
							        	String newAttrValue=_Utils.getCodeNamev2(fieldValue.toString(),codeList);
							        	map.put(newColumnName, newAttrValue);
						        	}else {
							        	String newAttrValue= _Utils.getCodeName(fieldValue.toString(),codeList);
							        	map.put(newColumnName, newAttrValue);
						        	}
									//map.put(columnName, newValue);
					        	}
					            break;
					        case dateformat:
					        	for(Map<String,Object> map:list) {
					        		Object fieldValue=map.get(columnName);
									if(fieldValue==null) {
										fieldValue="";
									}
									Object newValue=fieldValue;
									newValue= formatDate(fieldValue,column.getFromPattern(),column.getToPattern());
									map.put(columnName, newValue);
					        	}
					            break;
					        case numberformat:
					        	for(Map<String,Object> map:list) {
					        		Object fieldValue=map.get(columnName);
									if(fieldValue==null) {
										fieldValue="";
									}
									Object newValue=fieldValue;
									newValue= formatNumber(fieldValue.toString(),column.getPattern(),column.getFormula());
									map.put(columnName, newValue);
					        	}
					            break;
					        case replace:
					        	codeList = sysCodeService.query(codeKey);
					        	for(Map<String,Object> map:list) {
					        		Object fieldValue=map.get(columnName);
									if(fieldValue==null) {
										fieldValue="";
									}
									Object newValue=fieldValue;
									newValue= replace(fieldValue.toString(),codeList);
									map.put(columnName, newValue);
					        	}
					            break;
					            
//					        case qrcode_desensitization:
//								newValue=ObjectTranscoder.qrcode_desensitization(fieldValue.toString());
//					            break;  
//					        case download_url:
//					        	newValue=ObjectTranscoder.download_url_desensitization(column.getPattern(),map);
//					        	break; 
					        default:
					        	break;
					    }
				}catch(Exception e){
					log.error(ExceptionPrintUtils.getTrace(e));
				}
			}
		}
	}
	/**
	 * replace
	 * @param source
	 * @return
	 */
	private String replace(String source,List<Map<String, Object>> codeList){
		String newValue=source;
		if(codeList!=null){
			for(Map<String, Object> code:codeList){
				String code_value = (String)code.get("codeValue");
				String code_name = (String)code.get("codeName");
				newValue=newValue.replaceAll(code_value, code_name);
			}
		}
		return newValue;
	}
	
	private String download_url_desensitization(String pattern,Map<String,Object> map){
		if(pattern!=null) {
			GenericTokenParser parser = new GenericTokenParser("${", "}", new TokenHandler() {
				@Override
				public String handleToken(String content) {
					return map.get(content).toString();
				}
			});
			return parser.parse(pattern);
		}
		return "";
	}
	
	/**
	 * qrcode脱敏
	 */
	private String qrcode_desensitization(String source){
        return source.substring(0,9)+"****";
	}
	/**
	 * 格式化时间戳
	 * @param source
	 * @param fromPattern
	 * @param toPattern
	 * @return
	 */
	private Object formatDate(Object source,String fromPattern,String toPattern){
		Object newValue=source;
		SimpleDateFormat formatter = new SimpleDateFormat(toPattern);//非线程安全不能共享变量
		if(source instanceof Date){
			newValue=formatter.format(source);
		}else if(source instanceof LocalDateTime){
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(toPattern);
            newValue=((LocalDateTime) source).format(dateTimeFormatter);
        }else if(source.getClass()==String.class){
			try {
				Date date = DateUtils.parseDate(source.toString(), fromPattern);
				newValue=formatter.format(date);
			} catch (ParseException e) {
			}
		}
        return newValue;
	}
	/**
	 * 格式化数字
	 * @param source
	 * @param pattern
	 * @return
	 */
	private Object formatNumber(Object source,String pattern,String formula){
		Object newValue=source;
		DecimalFormat format=new DecimalFormat(pattern);
		if(source instanceof Number){
			newValue=format.format(source);
		}else if(source.getClass()== String.class){
			newValue=format.format(new Double(source.toString()));
		}
		return newValue;
	}
	/**
	 * 数字运算 add +, divide /,multiply *
	 * @param source
	 * @return
	 */
	private static BigDecimal operationNumber(BigDecimal source,List<String> operationList){
		if(operationList!=null&&operationList.size()>0){
			try {
				for(String operation:operationList){
					String s []=operation.split(",");
					String key=s[0];
					String value=s[1];
					BigDecimal bd=new BigDecimal(value);
					Method m=source.getClass().getMethod(key, BigDecimal.class);
					source=(BigDecimal)m.invoke(source, bd);
				}
			} catch (Exception e) {
				log.error(ExceptionPrintUtils.getTrace(e));
			}
		}
		return source;
	}
	
	
	/**
	 * 数据脱敏
	 * @return
	 */
	private String desensitization(){
		return null;
	}
	
}
